﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//补充知识：select new{F1=.., ..} 这是利用了匿名类对象的特性
namespace _08.linq
{
    //linq，使用sql语句查询集合！
    //如：from m in collection where m.F >8 select m;  如果并列条件，使用&&。
    //还可以使用扩展方法的写法 collection.Where()
    class Program
    {
        // 注意LINQ的查询语句只有在用到返回值的时候才会执行！延迟执行！
        // LINQ的前提，对象必须实现了IEnumerable接口！！！
        // LINQ必须以select或者group by结尾！！！
        static void Main(string[] args)
        {
            //SelectDemo();
            //GroupDemo();
            //JoinDemo();
            LetDemo();

            Console.ReadKey();
        }

        /**
         * 基本查询语法
         */
        static void SelectDemo()
        {
            int[] arr = { 15, 2, 6, 9, 7, 10, 11, 8 };
            //var res = from m in arr where m % 2 == 0 && m % 3 == 0 orderby m descending select m;
            var res = from m in arr where m % 2 == 0 || m % 3 == 0 orderby m descending select m;

            //强制执行LINQ语句 - 类似Java8 stream中的最终方法。
            res.Count();
            res.ToArray();
            res.ToList();

            foreach (var i in res)
            {
                Console.Write("{0}, ", i);
            }
            Console.WriteLine();

            //等同于使用扩展方法 - 务必注意int[]本身没有OrderBy之类的方法，都是System.Linq给扩展的！
            var res2 = arr.Where(i => i % 2 == 0).OrderByDescending((i) => i).Select(i => i);
            foreach (var i in res2)
            {
                Console.Write("{0}, ", i);
            }
            Console.WriteLine();
        }

        /**
         * Group查询。
         * 最基本的就是 group element by element.field。
         * 还可以添加查询，group . by .. into xx where xx...。
         */
        static void GroupDemo()
        {
            List<User> list = new List<User>();
            list.Add(new User() { Name = "aaa", City = "Pek" });
            list.Add(new User() { Name = "bbb", City = "Sh" });
            list.Add(new User() { Name = "ccc", City = "Sh" });
            list.Add(new User() { Name = "ddd", City = "Pek" });
            list.Add(new User() { Name = "eee", City = "Pek" });
            list.Add(new User() { Name = "fff", City = "Sh" });
            list.Add(new User() { Name = "ggg", City = "Pek" });

            var res = from u in list
                      group u by u.City; //group操作，

            foreach (var g in res)
            {
                Console.WriteLine(g.Key);
                foreach (var u in g)
                {
                    Console.WriteLine("\t{0}", u);
                }
            }

            //看看group by + into + where + select new
            var res2 = from u in list
                       group u by u.City into agroup //into 就是把每组当成一个变量
                       where agroup.Count() > 3
                       select new { key = agroup.Key, count = agroup.Count() };

            Console.WriteLine("res2.Count(): {0}", res2.Count());
            foreach (var i in res2)
            {
                Console.WriteLine("res2: key={0}, count={1}", i.key, i.count);
            }
        }

        /**
         * Join查询 - 条件关键字on，判断相等需要使用equals关键字！
         */
        static void JoinDemo()
        {
            List<User> users = new List<User>();
            users.Add(new User() { Name = "aaa", City = "Pek" });
            users.Add(new User() { Name = "bbb", City = "Sh" });
            users.Add(new User() { Name = "ccc", City = "Sh" });
            users.Add(new User() { Name = "ddd", City = "Pek" });
            users.Add(new User() { Name = "eee", City = "Pek" });
            users.Add(new User() { Name = "fff", City = "Sh" });
            users.Add(new User() { Name = "ggg", City = "Pek" });

            List<Employee> employees = new List<Employee>();
            employees.Add(new Employee() { ID = 1, Name = "aaa" });
            employees.Add(new Employee() { ID = 2, Name = "bbb" });
            employees.Add(new Employee() { ID = 3, Name = "ccc" });
            employees.Add(new Employee() { ID = 4, Name = "ddd" });
            employees.Add(new Employee() { ID = 5, Name = "eee" });
            employees.Add(new Employee() { ID = 6, Name = "fff" });
            employees.Add(new Employee() { ID = 99, Name = "zzz" });

            var res = from u in users
                      join e in employees
                      on u.Name equals e.Name
                      select new { zName = u.Name, zID = e.ID, zCity = u.City };

            foreach (var i in res)
            {
                Console.WriteLine(i); //匿名类型
                //i.zCity;
                //i.zID;
                //i.zName;
            }
        }

        /**
         * Let示例 - 可以让后面继续从let中from 或者select！
         */
        static void LetDemo()
        {
            string[] arr = { "hello world", "it's your job", "oh no!" };
            var res = from s in arr
                      let words = s.Split(' ') //为后面所用
                      from word in words
                      where word.Length > 3
                      select word.ToUpper()
                ;

            foreach (var i in res)
            {
                Console.WriteLine(i);
            }
        }
    }

    class User
    {
        public string Name { get; set; }
        public string City { get; set; }

        public override string ToString()
        {
            return string.Format("{0} from {1}", Name, City);
        }
    }

    class Employee
    {
        public string Name { get; set; }
        public int ID { get; set; }
        public override string ToString()
        {
            return string.Format("ID:{0,5}, Name:{1,10}", ID, Name);
        }
    }
}
